package com.cn.springcloudwechat.common.utils.weixin.api;

import com.cn.springcloudwechat.common.utils.HttpPost;
import com.cn.springcloudwechat.common.utils.base.Const;
import com.cn.springcloudwechat.common.utils.HttpPostUtil;
import com.cn.springcloudwechat.common.utils.tobyte.ToByte;
import com.cn.springcloudwechat.common.utils.weixin.core.JsonMsgBuilder;
import com.cn.springcloudwechat.common.utils.weixin.exception.WechatApiException;
import com.cn.springcloudwechat.common.utils.weixin.session.AccessTokenMemoryCache;
import com.cn.springcloudwechat.common.utils.weixin.session.JSTicketMemoryCache;
import com.cn.springcloudwechat.common.utils.weixin.session.MemoryCache;
import com.cn.springcloudwechat.common.utils.weixin.util.HttpTool;
import com.cn.springcloudwechat.common.utils.weixin.vo.ApiResult;
import com.cn.springcloudwechat.common.utils.weixin.vo.MPAccount;
import com.cn.springcloudwechat.common.utils.weixin.vo.api.*;
import com.cn.springcloudwechat.common.utils.weixin.weixinEntity.weiXinPicTextEntity.WeiXinPicTextEntity;
import com.cn.springcloudwechat.model.weixin.user.Follower;
import net.sf.json.JSONObject;
import org.nutz.castor.Castors;
import org.nutz.json.Json;
import org.nutz.json.JsonFormat;
import org.nutz.lang.Lang;
import org.nutz.lang.Strings;
import org.nutz.lang.util.NutMap;
import org.nutz.log.Log;
import org.nutz.log.Logs;
import org.springframework.util.StringUtils;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.*;

/**
 * 微信公众平台所有接口实现
 * 
 * @创建者 x.c
 * @地址 成都云函科技有限公司
 * @时间 2017年12月15日
 * @版本 v1.0.0
 */
@SuppressWarnings("unchecked")
public class WechatAPIImpl implements WechatAPI {



	private static final Log log = Logs.get();

	static int RETRY_COUNT = 3;

	static MemoryCache<AccessToken> _atmc;

	static MemoryCache<JSTicket> _jstmc;

	private MPAccount mpAct;

	public WechatAPIImpl(MPAccount mpAct) {
		this.mpAct = mpAct;
		synchronized (this) {
			if (_atmc == null) {
				_atmc = new AccessTokenMemoryCache();
			}
			if (_jstmc == null) {
				_jstmc = new JSTicketMemoryCache();
			}
		}
	}

	/**
	 * WechatAPI 实现方法
	 * 
	 * @param mpAct
	 *            微信公众号信息{@link MPAccount}
	 * @return 对应的API
	 */
	public static WechatAPI create(MPAccount mpAct) {
		return new WechatAPIImpl(mpAct);
	}

	private String mergeUrl(String url, Object... values) {
		if (!Lang.isEmpty(values)) {
			return wechatapi + String.format(url, values);
		}
		return wechatapi + url;
	}

	private String mergeCustomerUrl(String url, Object... values) {
		if (!Lang.isEmpty(values)) {
			return wechatCustomer + String.format(url, values);
		}
		return wechatapi + url;
	}

	private String mergethumbUrl(String url, Object... values) {
		if (!Lang.isEmpty(values)) {
			return wechatThumbFile + String.format(url, values);
		}
		return wechatapi + url;
	}

	private String mergeQRUrl(String url, Object... values) {
		if (!Lang.isEmpty(values)) {
			return wechatQRapi + String.format(url, values);
		}
		return wechatQRapi + url;
	}

	private String mergeAuthUrl(String url, Object... values) {
		if (!Lang.isEmpty(values)) {
			return wechatauthapi + String.format(url, values);
		}
		return wechatapi + url;
	}

	/**
	 * 强制刷新微信服务凭证
	 */
	private synchronized void refreshAccessToken() {
		String url = mergeUrl(get_at, mpAct.getAppId(), mpAct.getAppSecret());
		AccessToken at = null;
		ApiResult ar = null;
		for (int i = 0; i < RETRY_COUNT; i++) {
			ar = ApiResult.create(HttpTool.get(url));
			if (ar.isSuccess()) {
				at = Json.fromJson(AccessToken.class, ar.getJson());
				_atmc.set(mpAct.getMpId(), at);
			}

			if (at != null && at.isAvailable()) {
				return;
			}

			log.errorf("Get mp[%s]access_token failed. There try %d items.", mpAct.getMpId(), i + 1);

		}

		throw Lang.wrapThrow(new WechatApiException(ar.getJson()));
	}

	private synchronized void refreshJSTicket() {
		String url = mergeUrl(js_ticket + getAccessToken());
		JSTicket jst = null;
		ApiResult ar = null;
		for (int i = 0; i < RETRY_COUNT; i++) {
			ar = ApiResult.create(HttpTool.get(url));
			if (ar.isSuccess()) {
				jst = Json.fromJson(JSTicket.class, ar.getJson());
				_jstmc.set(mpAct.getMpId(), jst);
			}

			if (jst != null && jst.isAvailable()) {
				return;
			}

			log.errorf("Get mp[%s] JSSDK ticket failed. There try %d items.", mpAct.getMpId(), i + 1);

		}

		throw Lang.wrapThrow(new WechatApiException(ar.getJson()));
	}

	/**
	 * 微信上传素材的请求方法
	 * 
	 * @param url
	 *            微信上传临时素材的接口url
	 * @param filePath
	 *            要上传的文件
	 * @return String 上传成功后，微信服务器返回的消息
	 */
	public static String httpRequest(String url, String filePath) {
		String result = null;
		HttpURLConnection downloadCon = null;
		InputStream inputStream = null;
		BufferedReader reader = null;
		try {
			URL urlFile = new URL(filePath);
			downloadCon = (HttpURLConnection) urlFile.openConnection();
			inputStream = downloadCon.getInputStream();

			URL urlObj = new URL(url);
			HttpURLConnection con = (HttpURLConnection) urlObj.openConnection();
			/**
			 * 设置关键值
			 */
			con.setRequestMethod("POST"); // 以Post方式提交表单，默认get方式
			con.setDoInput(true);
			con.setDoOutput(true);
			con.setUseCaches(false); // post方式不能使用缓存
			// 设置请求头信息
			con.setRequestProperty("Connection", "Keep-Alive");
			con.setRequestProperty("Charset", "UTF-8");
			// 设置边界
			String BOUNDARY = "---------------------------" + System.currentTimeMillis();
			con.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);
			// 请求正文信息
			// 第一部分：
			StringBuilder sb = new StringBuilder();
			String regex = ".*/([^\\.]+)";
			sb.append("--"); // 必须多两道线
			sb.append(BOUNDARY);
			sb.append("\r\n");
			sb.append("Content-Disposition: form-data;name=\"media\";filename=\"" + filePath.replaceAll(regex, "$1")
					+ "\"\r\n");
			sb.append("Content-Type:application/octet-stream\r\n\r\n");
			byte[] head = sb.toString().getBytes("utf-8");
			// 获得输出流
			OutputStream out = new DataOutputStream(con.getOutputStream());
			// 输出表头
			out.write(head);
			// 文件正文部分
			// 把文件已流文件的方式 推入到url中
			int bytes = 0;
			byte[] bufferOut = new byte[1024];
			while ((bytes = inputStream.read(bufferOut)) != -1) {
				out.write(bufferOut, 0, bytes);
			}
			inputStream.close();
			// 结尾部分
			byte[] foot = ("\r\n--" + BOUNDARY + "--\r\n").getBytes("utf-8");// 定义最后数据分隔线
			out.write(foot);

			out.flush();
			out.close();

			StringBuffer buffer = new StringBuffer();
			// 定义BufferedReader输入流来读取URL的响应
			System.out.println("获取相应码=" + con.getResponseCode());
			reader = new BufferedReader(new InputStreamReader(con.getInputStream()));
			String line = null;
			while ((line = reader.readLine()) != null) {
				buffer.append(line);
			}
			if (result == null) {
				result = buffer.toString();
			}
		} catch (IOException e) {
			e.printStackTrace();
			return null;
		} finally {
			if (reader != null) {
				try {
					reader.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return result;
	}

	// 获取AccessToken
	@Override
	public String getAccessToken() {
		AccessToken at = _atmc.get(mpAct.getMpId());
		if (at == null || !at.isAvailable()) {
			refreshAccessToken();
			at = _atmc.get(mpAct.getMpId());
		}
		System.out.println("accessToken=" + at.getAccessToken());
		return at.getAccessToken();
	}

	@Override
	public List<String> getServerIps() {
		String url = mergeUrl(cb_ips + getAccessToken());
		ApiResult ar = null;
		for (int i = 0; i < RETRY_COUNT; i++) {
			ar = ApiResult.create(HttpTool.get(url));
			if (ar.isSuccess()) {
				return Json.fromJsonAsList(String.class, Json.toJson(ar.get("ip_list")));
			}

			log.errorf("Get mp[%s] server ips failed. There try %d items.", mpAct.getMpId(), i + 1);
		}

		throw Lang.wrapThrow(new WechatApiException(ar.getJson()));
	}

	@Override
	public String getShortUrl(String longUrl) {
		String url = mergeUrl(short_url + getAccessToken());
		String data = "{\"action\":\"long2short\",\"long_url\":\"" + longUrl + "\"}";
		ApiResult ar = null;
		for (int i = 0; i < RETRY_COUNT; i++) {
			ar = ApiResult.create(HttpTool.post(url, data));
			if (ar.isSuccess()) {
				return String.valueOf(ar.get("short_url"));
			}

			log.errorf("Create mp[%p] short url failed. There try %d items.", mpAct.getMpId(), i);
		}

		throw Lang.wrapThrow(new WechatApiException(ar.getJson()));
	}

	@Override
	public String getJSTicket() {
		JSTicket jst = _jstmc.get(mpAct.getMpId());
		if (jst == null || !jst.isAvailable()) {
			refreshJSTicket();
			jst = _jstmc.get(mpAct.getMpId());
		}
		return jst.getTicket();
	}

	@Override
	public List<Menu> getMenu() {
		String url = mergeUrl(query_menu + getAccessToken());
		ApiResult ar = null;
		for (int i = 0; i < RETRY_COUNT; i++) {
			ar = ApiResult.create(HttpTool.get(url));
			if (ar.isSuccess()) {
				Map<String, Object> button = Json.fromJson(Map.class, Json.toJson(ar.get("menu")));
				return Json.fromJsonAsList(Menu.class, Json.toJson(button.get("button")));
			}

			// 菜单为空
			if (ar.getErrCode().intValue() == 46003) {
				return null;
			}

			log.errorf("Get mp[%s] custom menu failed. There try %d items.", mpAct.getAppId(), i + 1);
		}

		throw Lang.wrapThrow(new WechatApiException(ar.getJson()));
	}

	@Override
	public boolean createMenu(Menu... menu) {
		String url = mergeUrl(create_menu + getAccessToken());
		Map<String, Object> body = new HashMap<String, Object>();
		body.put("button", menu);
		String data = Json.toJson(body, JsonFormat.compact());
		System.out.println(data);
		ApiResult ar = null;
		for (int i = 0; i < RETRY_COUNT; i++) {
			ar = ApiResult.create(HttpTool.post(url, data));
			if (ar.isSuccess()) {
				return true;
			}
			log.errorf("Create mp[%s] custom menu failed. There try %d items.", mpAct.getAppId(), i + 1);
		}
		throw Lang.wrapThrow(new WechatApiException(ar.getJson()));
	}

	@Override
	public boolean delMenu() {
		String url = mergeUrl(del_menu + getAccessToken());
		ApiResult ar = null;
		for (int i = 0; i < RETRY_COUNT; i++) {
			ar = ApiResult.create(HttpTool.get(url));
			if (ar.isSuccess()) {
				return true;
			}

			log.errorf("Delete mp[%s] custom menu failed. There try %d items.", mpAct.getMpId(), i + 1);
		}

		throw Lang.wrapThrow(new WechatApiException(ar.getJson()));
	}

	/**
	 * 上传临时素材
	 * 
	 * @Override public Media upMedia(String type, File media) { String url =
	 *           mergeUrl(upload_media, getAccessToken(), type); ApiResult ar =
	 *           null; for (int i = 0; i < RETRY_COUNT; i++) { ar =
	 *           ApiResult.create(HttpTool.upload(url, media)); if
	 *           (ar.isSuccess()) { return Json.fromJson(Media.class,
	 *           ar.getJson()); }
	 * 
	 *           log.errorf("Upload mp[%s] media failed. There try %d items.",
	 *           mpAct.getMpId(), i + 1); }
	 * 
	 *           throw Lang.wrapThrow(new WechatApiException(ar.getJson())); }
	 */

	@Override
	public File dlMedia(String mediaId) {
		String url = mergeUrl(get_media, getAccessToken(), mediaId);
		ApiResult ar = null;
		for (int i = 0; i < RETRY_COUNT; i++) {
			Object tmp = HttpTool.download(url);
			if (tmp instanceof File) {
				return (File) tmp;
			}

			ar = ApiResult.create((String) tmp);
			log.errorf("Download mp[%s] media failed. There try %d items.", mpAct.getMpId(), i);
		}

		throw Lang.wrapThrow(new WechatApiException(ar.getJson()));
	}

	@Override
	public int createGroup(String name) {
		String url = mergeUrl(create_groups + getAccessToken());
		String data = "{\"group\":{\"name\":\"" + name + "\"}}";
		ApiResult ar = null;
		for (int i = 0; i < RETRY_COUNT; i++) {
			ar = ApiResult.create(HttpTool.post(url, data));
			if (ar.isSuccess()) {
				Groups g = Json.fromJson(Groups.class, Json.toJson(ar.get("group")));
				return g.getId();
			}

			log.errorf("Create mp[%s] group name[%s] failed. There try %d items.", mpAct.getMpId(), name, i);
		}

		throw Lang.wrapThrow(new WechatApiException(ar.getJson()));
	}

	@Override
	public List<Groups> getGroups() {
		String url = mergeUrl(get_groups + getAccessToken());
		ApiResult ar = null;
		for (int i = 0; i < RETRY_COUNT; i++) {
			ar = ApiResult.create(HttpTool.get(url));
			if (ar.isSuccess()) {
				return Json.fromJsonAsList(Groups.class, Json.toJson(ar.get("groups")));
			}

			log.errorf("Get mp[%s] groups failed. There try %d items.", mpAct.getMpId(), i);
		}

		throw Lang.wrapThrow(new WechatApiException(ar.getJson()));
	}

	@Override
	public int getGroup(String openId) {
		String url = mergeUrl(get_member_group + getAccessToken());
		String data = "{\"openid\":\"" + openId + "\"}";
		ApiResult ar = null;
		for (int i = 0; i < RETRY_COUNT; i++) {
			ar = ApiResult.create(HttpTool.post(url, data));
			if (ar.isSuccess()) {
				return Integer.parseInt(String.valueOf(ar.get("groupid")));
			}

			log.errorf("Get mp[%s] openId[%s] groups failed. There try %d items.", mpAct.getMpId(), openId, i);
		}

		throw Lang.wrapThrow(new WechatApiException(ar.getJson()));
	}

	@Override
	public boolean renGroups(int id, String name) {
		String url = mergeUrl(update_group + getAccessToken());
		String data = "{\"group\":{\"id\":" + id + ",\"name\":\"" + name + "\"}}";
		ApiResult ar = null;
		for (int i = 0; i < RETRY_COUNT; i++) {
			ar = ApiResult.create(HttpTool.post(url, data));
			if (ar.isSuccess()) {
				return true;
			}

			log.errorf("Rename mp[%s] groups[%d-%s] failed. There try %d items.", mpAct.getMpId(), id, name, i);
		}

		throw Lang.wrapThrow(new WechatApiException(ar.getJson()));
	}

	@Override
	public boolean move2Group(String openId, int groupId) {
		String url = mergeUrl(update_member_group + getAccessToken());
		String data = "{\"openid\":\"" + openId + "\",\"to_groupid\":" + groupId + "}";
		ApiResult ar = null;
		for (int i = 0; i < RETRY_COUNT; i++) {
			ar = ApiResult.create(HttpTool.post(url, data));
			if (ar.isSuccess()) {
				return true;
			}

			log.errorf("Move mp[%s] openId[%s] to groups[%d] failed. There try %d items.", mpAct.getMpId(), openId,
					groupId, i);
		}

		throw Lang.wrapThrow(new WechatApiException(ar.getJson()));
	}

	@Override
	public boolean batchMove2Group(Collection<String> openIds, int groupId) {
		String url = mergeUrl(update_members_group + getAccessToken());
		Map<String, Object> data = new HashMap<String, Object>();
		data.put("openid_list", Json.toJson(openIds));
		data.put("to_groupid", groupId);
		ApiResult ar = null;
		for (int i = 0; i < RETRY_COUNT; i++) {
			ar = ApiResult.create(HttpTool.post(url, Json.toJson(data, JsonFormat.compact())));
			if (ar.isSuccess()) {
				return true;
			}

			log.errorf("Move mp[%s] openIds to groups[%d] failed. There try %d items.", mpAct.getMpId(), groupId, i);
		}

		throw Lang.wrapThrow(new WechatApiException(ar.getJson()));
	}

	@Override
	public boolean delGroup(int id) {
		String url = mergeUrl(delete_groups + getAccessToken());
		String data = "{\"group\":{\"id\":" + id + "}}";
		ApiResult ar = null;
		for (int i = 0; i < RETRY_COUNT; i++) {
			ar = ApiResult.create(HttpTool.post(url, data));
			if (ar.isSuccess()) {
				return true;
			}

			log.errorf("Delete mp[%s] groups[%d] failed. There try %d items.", mpAct.getMpId(), id, i);
		}

		throw Lang.wrapThrow(new WechatApiException(ar.getJson()));
	}

	// 获取二维码必要的ticket
	@Override
	public QRTicket createQR(Object sceneId, int expireSeconds) {
		String url = mergeUrl(create_qrcode + getAccessToken());
		ApiResult ar = null;
		NutMap data = new NutMap();
		NutMap scene;
		// 临时二维码
		if (expireSeconds > 0) {
			data.put("expire_seconds", expireSeconds);
			if (sceneId instanceof Number) {
				data.put("action_name", "QR_SCENE");
				scene = Lang.map("scene_id", Castors.me().castTo(sceneId, Integer.class));
			}else{
				data.put("action_name", "QR_STR_SCENE");
				scene = Lang.map("scene_str", sceneId.toString());
			}
		}
		// 永久二维码
		else if (sceneId instanceof Number) {
			data.put("action_name", "QR_LIMIT_SCENE");
			scene = Lang.map("scene_id", Castors.me().castTo(sceneId, Integer.class));
		}
		// 永久字符串二维码
		else {
			data.put("action_name", "QR_LIMIT_STR_SCENE");
			scene = Lang.map("scene_str", sceneId.toString());
		}
		data.put("action_info", Lang.map("scene", scene));
		for (int i = 0; i < RETRY_COUNT; i++) {
			String param=Json.toJson(data, JsonFormat.compact());
            System.out.println("生成二维码参数:"+param);
			ar = ApiResult.create(HttpTool.post(url,param ));
			if (ar.isSuccess()) {
				return Json.fromJson(QRTicket.class, Json.toJson(ar.getContent()));
			}

			log.infof("Create mp[%s] scene[%s] qrcode failed. There try %d items.", mpAct.getMpId(),
					data.get("action_name"), i);
		}

		throw Lang.wrapThrow(new WechatApiException(ar.getJson()));
	}

	/**
	 * 获取带参数二维码
	 */
	@Override
	public Map<String,Object> getQR(String ticket) {
		String url = mergeQRUrl(show_qrcode + ticket);
		System.err.println("获取二维码url:" + url);
		Map<String,Object> map=new HashMap<>();
		map.put("url",url);
		map.put("byte", HttpPostUtil.sendGetPic(url));
		return map;
	}

	@Override
	public boolean updateRemark(String openId, String remark) {
		String url = mergeUrl(user_remark + getAccessToken());
		ApiResult ar = null;
		String data = "{\"openid\":\"" + openId + "\",\"remark\":\"" + remark + "\"}";
		for (int i = 0; i < RETRY_COUNT; i++) {
			ar = ApiResult.create(HttpTool.post(url, data));
			if (ar.isSuccess()) {
				return true;
			}

			log.errorf("Update mp[%s] user[%s] remark[%s] failed. There try %d items.", mpAct.getMpId(), openId, remark,
					i);
		}

		throw Lang.wrapThrow(new WechatApiException(ar.getJson()));
	}

	/**
	 * 获取粉丝列表
	 */

	@Override
	public FollowList getFollowerList(String nextOpenId) {
		String url = mergeUrl(user_list, getAccessToken(), Strings.sNull(nextOpenId, ""));
		ApiResult ar = null;
		for (int i = 0; i < RETRY_COUNT; i++) {
			ar = ApiResult.create(HttpTool.get(url));
			if (ar.isSuccess()) {
				FollowList fl = Json.fromJson(FollowList.class, ar.getJson());
				Map<String, Object> openid = (Map<String, Object>) ar.get("data");
				fl.setOpenIds(Json.fromJson(List.class, Json.toJson(openid.get("openid"))));
				return fl;
			}

			log.infof("Get mp[%s] follow list failed. There try %d items.", mpAct.getMpId(), i);
		}
		throw Lang.wrapThrow(new WechatApiException(ar.getJson()));
	}

	/**
	 * 获取某个粉丝信息
	 */
	@Override
	public Follower getFollower(String openId, String lang) {
		String accessToken = getAccessToken();
		String url = mergeUrl(user_info, accessToken, openId, Strings.sNull(lang, "zh_CN"));
		ApiResult ar = null;
		for (int i = 0; i < RETRY_COUNT; i++) {
			ar = ApiResult.create(HttpTool.get(url));
			if (ar.isSuccess()) {
				return Json.fromJson(Follower.class, ar.getJson());
			}

			log.errorf("Get mp[%s] follower[%s] information failed. There try %d items.", mpAct.getMpId(), openId, i);
		}

		throw Lang.wrapThrow(new WechatApiException(ar.getJson()));
	}

	/**
	 * 批量获取用户基本信息
	 */
	@Override
	public List<Follower> getFollowers(Collection<Follower2> users) {
		String url = mergeUrl(batch_user_info + getAccessToken());
		ApiResult ar = null;
		String data = Json.toJson(Lang.map("user_list", users), JsonFormat.compact());
		for (int i = 0; i < RETRY_COUNT; i++) {
			ar = ApiResult.create(HttpTool.post(url, data));
			if (ar.isSuccess()) {
				return Json.fromJsonAsList(Follower.class, Json.toJson(ar.get("user_info_list")));
			}

			log.errorf("Get mp[%s] followers information failed. There try %d items.", mpAct.getMpId(), i);
		}

		throw Lang.wrapThrow(new WechatApiException(ar.getJson()));
	}

	@Override
	public boolean setIndustry(int id1, int id2) {
		String url = mergeUrl(set_industry + getAccessToken());
		ApiResult ar = null;
		String data = "{\"industry_id1\":\"" + id1 + "\",\"industry_id2\":\"" + id2 + "\"}";
		for (int i = 0; i < RETRY_COUNT; i++) {
			ar = ApiResult.create(HttpTool.post(url, data));
			if (ar.isSuccess()) {
				return true;
			}

			log.errorf("Set mp[%s] template industry failed. There try %d items.", mpAct.getMpId(), i);
		}

		throw Lang.wrapThrow(new WechatApiException(ar.getJson()));
	}

	@Override
	public String getTemplateId(String tmlShortId) {
		String url = mergeUrl(add_template + getAccessToken());
		ApiResult ar = null;
		String data = "{\"template_id_short\":\"" + tmlShortId + "\"}";
		for (int i = 0; i < RETRY_COUNT; i++) {
			ar = ApiResult.create(HttpTool.post(url, data));
			if (ar.isSuccess()) {
				return String.valueOf(ar.get("template_id"));
			}

			log.errorf("Get mp[%s] template id failed. There try %d items.", mpAct.getMpId(), i);
		}

		throw Lang.wrapThrow(new WechatApiException(ar.getJson()));
	}


	/**
	 * 发送模板消息
	 */
	@Override
	public long sendTemplateMsg(String openId, String tmlId, String topColor, String url, Template... tmls) {
		String apiurl = mergeUrl(send_template + getAccessToken());
		ApiResult ar = null;
		String data = JsonMsgBuilder.create().template(openId, tmlId, topColor, url, tmls).build();
		for (int i = 0; i < RETRY_COUNT; i++) {
			ar = ApiResult.create(HttpTool.post(apiurl, data));
			if (ar.isSuccess()) {
				return Long.valueOf(ar.get("msgid").toString());
			}

			log.errorf("Send mp[%s] template socketMessage failed. There try %d items.", mpAct.getMpId(), i);
		}

		throw Lang.wrapThrow(new WechatApiException(ar.getJson()));
	}

	/**
	 * 获取模板id
	 */
	@Override
	public String getTemplateId() {
		String apiurl = mergeAuthUrl(get_my_template + getAccessToken());
		ApiResult ar = null;
		ar = ApiResult.create(HttpTool.get(apiurl));
		return ar.toString();
	}

	@Override
	public String getOpenId(String code) {
		ApiResult ar = null;
		try{
			String url = mergeAuthUrl(get_user_openid, mpAct.getAppId(), mpAct.getAppSecret(), code);
			ar = ApiResult.create(HttpTool.get(url));
			if (ar.isSuccess()) {
				if (ar.get("errcode") == null) {
					return String.valueOf(ar.get("openid"));
				}
			}
		}catch (Exception e){
			e.printStackTrace();
		}

		return ar.toString();
	}

	/*
	 * 上传临时素材或者永久素材
	 */
	@Override
	public String getMediaId(String path, String type, String index) {
		String url = "";
		if (index.equals("1")) {
			// 临时
			System.out.println("新增临时图片");
			url = mergeUrl(upload_media, getAccessToken(), type);
		} else if (index.equals("2")) {
			// 永久
			System.out.println("新增永久图片");
			url = mergeUrl(upload_media_forever, getAccessToken(), type);
		} else if (index.equals("3")) {
			System.out.println("新增永久图文消息永久图片");
			// 图文消息永久图片
			url = mergeUrl(upload_ImgText, getAccessToken());
		} else if (index.equals("4")) {
			// 图文消息中缩略图
			// 两个均可用 返回的media_id可作为缩略图
			// url=mergeUrl(upload_media_forever, getAccessToken(), type);
			// 返回thumb_midia（大概是这个字段可作为缩略图）
			url = mergethumbUrl(upload_thumb_media, getAccessToken());
		}
		String result = HttpPostUtil.httpRequest(url, path);
		return result;
	}

	// 主动推送消息给客户(48小时无响应无法发送)
	/*
	 * @Override public String sendMessage(String openId, String socketMessage) { //
	 * TODO Auto-generated method stub JSONObject jsonObject1 = new
	 * JSONObject(); jsonObject1.put("content", socketMessage); JSONObject
	 * joJsonObject = new JSONObject(); joJsonObject.put("touser", openId);
	 * joJsonObject.put("msgtype", "text"); joJsonObject.put("text",
	 * jsonObject1); System.out.println(joJsonObject); String path1 =
	 * String.format(Const.Win_Xin_Send_Message, getAccessToken()); String
	 * result = HttpPostUtil.sendPost(path1, joJsonObject.toString()); return
	 * result; }
	 */

	// 新增永久图文素材 未测试
	@Override
	public String uploadPicText(String title[], String thumb_media_id[], String author[], String digest[],
			String show_cover_pic[], String content[], String content_source_url[]) {
		JSONObject jsonObject = new JSONObject();
		List<Object> list = new ArrayList<>();
		for (int i = 0; i < title.length; i++) {
			WeiXinPicTextEntity weiXinPicTextEntity = new WeiXinPicTextEntity();
			weiXinPicTextEntity.setTitle(title[i]);
			weiXinPicTextEntity.setThumb_media_id(thumb_media_id[i]);
			weiXinPicTextEntity.setAuthor(author[i]);// 可以不传
			if (title.length == 1) {
				weiXinPicTextEntity.setDigest(digest[i]);// 图文摘要 单图才有 如果此处不传
															// 会有默认值
			}
			weiXinPicTextEntity.setShow_cover_pic(show_cover_pic[i]);// 1显示0不显示
			weiXinPicTextEntity.setContent(content[i]);// 图文消息内容 图片和文字都在里面html
			weiXinPicTextEntity.setContent_source_url(content_source_url[i]);
			list.add(weiXinPicTextEntity);
		}
		jsonObject.put("articles", list);
		System.out.println(jsonObject);
		String url = mergeUrl(upload_ImgTextURL, getAccessToken());
		String result = HttpPostUtil.sendPost(url, jsonObject);
		return result;
	}


	/**
	 * 创建标签
	 */
	@Override
	public String create_tag(String name) {
		JSONObject jsonObject = new JSONObject();
		JSONObject jsonObject2 = new JSONObject();
		jsonObject2.put("name", name);
		jsonObject.put("tag", jsonObject2);
		String url = mergeUrl(create_tag, getAccessToken());
		String result = HttpPostUtil.sendPost(url, jsonObject);
		return result;
	}

	/**
	 * 修改标签
	 */
	@Override
	public String update_tag(String id, String name) throws UnsupportedEncodingException {
		JSONObject jsonObject = new JSONObject();
		JSONObject jsonObject2 = new JSONObject();
		jsonObject2.put("id", id);
		jsonObject2.put("name", name);
		jsonObject.put("tag", jsonObject2);
		String url = mergeUrl(update_tag, getAccessToken());
		String result = HttpPostUtil.sendPostJSON(url, jsonObject);
		return result;
	}

	/**
	 * 删除标签
	 */
	@Override
	public String delete_tag(String id) throws UnsupportedEncodingException {
		JSONObject jsonObject = new JSONObject();
		JSONObject jsonObject2 = new JSONObject();
		jsonObject2.put("id", id);
		jsonObject.put("tag", jsonObject2);
		String url = mergeUrl(delete_tag, getAccessToken());
		String result = HttpPostUtil.sendPostJSON(url, jsonObject);
		return result;
	}

	/**
	 * 查询标签
	 */
	@Override
	public String quert_tag() {
		String url = mergeUrl(query_tag, getAccessToken());
		String result = HttpPostUtil.sendGet(url, null);
		return result;
	}

	/**
	 * 获取标签下粉丝列表(某个标签) tag_id 标签 open_id 从某个粉丝开始拉取 (不填默认从头拉取)
	 */
	@Override
	public String query_tag_user_list(String tag_id, String open_id) throws UnsupportedEncodingException {
		JSONObject jsonObject = new JSONObject();
		jsonObject.put("tagid", tag_id);
		// open_id可以为""
		jsonObject.put("open_id", open_id);
		String url = mergeUrl(query_tag_user_list, getAccessToken());
		String result = HttpPostUtil.sendPostJSON(url, jsonObject);
		return result;
	}

	/**
	 * 批量为用户打标签
	 * 
	 * @方法名:add_tag_user
	 * @描述:
	 * @param tag_id
	 * @param list
	 * @return
	 */
	@Override
	public String add_tag_user(String tag_id, List<String> list) throws UnsupportedEncodingException {
		JSONObject jsonObject = new JSONObject();
		jsonObject.put("tagid", tag_id);
		jsonObject.put("openid_list", list);
		String url = mergeUrl(add_tag_user, getAccessToken());
		String result = HttpPostUtil.sendPostJSON(url, jsonObject);
		return result;
	}

	/**
	 * 批量为用户取消标签
	 * 
	 * @方法名:channel_tag_user
	 * @描述:
	 * @param tag_id
	 * @param list
	 * @return
	 */
	@Override
	public String channel_tag_user(String tag_id, List<String> list) throws UnsupportedEncodingException {
		JSONObject jsonObject = new JSONObject();
		jsonObject.put("tagid", tag_id);
		jsonObject.put("openid_list", list);
		String url = mergeUrl(channel_tag_user, getAccessToken());
		String result = HttpPostUtil.sendPostJSON(url, jsonObject);
		return result;
	}

	/**
	 * 获取用户所在的标签
	 * 
	 * @方法名:get_tag_user
	 * @描述:
	 * @param open_id
	 * @return
	 */
	@Override
	public String get_tag_user(String open_id) throws UnsupportedEncodingException {
		JSONObject jsonObject = new JSONObject();
		jsonObject.put("openid", open_id);
		String url = mergeUrl(get_tag_user, getAccessToken());
		String result = HttpPostUtil.sendPostJSON(url, jsonObject);
		return result;
	}

	/**
	 * next_openid 可以为空 则默认从头拉取
	 */
	@Override
	public String get_user_list(String next_openid) {
		String url;
		if (StringUtils.isEmpty(next_openid)) {
			url = mergeUrl(get_user_list, getAccessToken());
		} else {
			url = mergeUrl(get_user_list + "&next_openid=%s", getAccessToken(), next_openid);
		}
		String result = HttpPostUtil.sendGet(url, null);
		return result;
	}

	/**
	 * 添加客户账号
	 * 
	 * @方法名:addCustomer
	 * @描述:
	 * @param kf_account
	 *            完整客服帐号，格式为：帐号前缀@公众号微信号，帐号前缀最多10个字符，必须是英文、数字字符或者下划线，后缀为公众号微信号，
	 *            长度不超过30个字符
	 * @param nickname
	 * @return
	 */
	@Override
	public String addCustomer(String kf_account, String nickname) throws UnsupportedEncodingException {
		JSONObject jsonObject = new JSONObject();
		jsonObject.put("kf_account", kf_account);
		jsonObject.put("nickname", nickname);
		String url = mergeCustomerUrl(add_customer, getAccessToken());
		System.out.println("url:" + url);
		System.out.println(jsonObject.toString());
		String result = HttpPostUtil.sendPostJSON(url, jsonObject);
		return result;
	}

	/**
	 * 绑定客户到微信
	 * 
	 * @方法名:bindingCustmoerWeixin
	 * @描述:
	 * @param kf_account
	 *            完整客服帐号，格式为：帐号前缀@公众号微信号，帐号前缀最多10个字符，必须是英文、数字字符或者下划线，后缀为公众号微信号，
	 *            长度不超过30个字符
	 * @param invite_wx
	 *            接收绑定邀请的客服微信号
	 * @return
	 */
	@Override
	public String bindingCustmoerWeixin(String kf_account, String invite_wx) throws UnsupportedEncodingException {
		JSONObject jsonObject = new JSONObject();
		jsonObject.put("kf_account", kf_account);
		jsonObject.put("invite_wx", invite_wx);
		String url = mergeUrl(binding_customer_weixin, getAccessToken());
		String result = HttpPostUtil.sendPostJSON(url, jsonObject);
		return result;
	}

	/**
	 * 上传客服头像
	 * 
	 * @方法名:uploadCustomerHeadurl
	 * @描述:
	 * @param kf_account
	 * @param path
	 * @return
	 */
	@Override
	public String uploadCustomerHeadurl(String kf_account, String path) {
		String url = mergeUrl(upload_customer_headurl, getAccessToken(), kf_account);
		String result = HttpPostUtil.httpRequest(url, path);
		return result;
	}

	/**
	 * 获取客户基本信息
	 * 
	 * @方法名:getCustomer
	 * @描述:
	 * @return
	 */
	@Override
	public String getCustomer() {
		String url = mergeUrl(get_customer, getAccessToken());
		String result = HttpPostUtil.sendGet(url, null);
		return result;
	}

	// 主动推送消息给客户(48小时无响应无法发送)
	@Override
	public String sendMessage(String openId, String message) {
		JSONObject jsonObject1 = new JSONObject();
		jsonObject1.put("content", message);
		JSONObject joJsonObject = new JSONObject();
		joJsonObject.put("touser", openId);
		joJsonObject.put("msgtype", "text");
		joJsonObject.put("text", jsonObject1);
		System.out.println(joJsonObject);
		String path1 = String.format(Const.Win_Xin_Send_Message, getAccessToken());
		String result = HttpPost.sendPost(path1, joJsonObject.toString());
		return result;
	}

	/**
	 * 修改客户信息
	 */
	@Override
	public String updateCustomer(String kf_account, String nickname) throws UnsupportedEncodingException {
		String url = mergeUrl(upload_customer_headurl, getAccessToken());
		JSONObject jsonObject = new JSONObject();
		jsonObject.put("kf_account", kf_account);
		jsonObject.put("nickname", nickname);
		String result = HttpPostUtil.sendPostJSON(url, jsonObject);
		return result;
	}

	/**
	 * 创建会话
	 */
	@Override
	public String createDialogue(String kf_account, String openid) throws UnsupportedEncodingException {
		String url = mergeCustomerUrl(create_dialogue_url, getAccessToken());
		JSONObject jsonObject = new JSONObject();
		jsonObject.put("kf_account", kf_account);
		jsonObject.put("openid", openid);
		String parm=jsonObject.toString();
		System.out.println("josn:"+parm);
		String result = HttpPostUtil.sendPostJSON(url, jsonObject);
		return result;
	}

	/**
	 * 关闭某个客户的会话
	 * 
	 * @方法名:deleteDialogue
	 * @描述:
	 * @param openid
	 * @return
	 */
	@Override
	public String deleteDialogue(String kf_account, String openid) throws UnsupportedEncodingException {
		String url = mergeCustomerUrl(delete_dialogue_url, getAccessToken());
		JSONObject jsonObject = new JSONObject();
		jsonObject.put("kf_account", kf_account);
		jsonObject.put("openid", openid);
		String result = HttpPostUtil.sendPostJSON(url, jsonObject);
		return result;
	}

	/**
	 * 获取客户会话状态
	 * 
	 * @方法名:getDialogueStatus
	 * @描述:
	 * @param openid
	 * @return kf_acount 正在接待的客服，为空表示没有人在接待 createtime 会话接入的时间
	 */
	@Override
	public String getDialogueStatus(String openid) {
		JSONObject jsonObject = new JSONObject();
		jsonObject.put("openid", openid);
		String url = mergeCustomerUrl(get_dialogue_status_url, getAccessToken(), jsonObject);
		String result = HttpPostUtil.sendGet(url, null);
		return result;
	}

	/**
	 * 获取客服会话列表
	 * 
	 * @方法名:getCustomerList
	 * @描述:
	 * @param kf_account
	 * @return
	 */
	@Override
	public String getCustomerList(String kf_account) {
		JSONObject jsonObject = new JSONObject();
		jsonObject.put("kf_account", kf_account);
		String url = mergeCustomerUrl(get_customer_list_url, getAccessToken(), jsonObject);
		String result = HttpPostUtil.sendGet(url, null);
		return result;
	}

	/**
	 * 获取客户未接入会话列表
	 * 
	 * @方法名:noDialogue
	 * @描述:
	 * @return
	 */
	@Override
	public String noDialogue() {
		String url = mergeCustomerUrl(no_dialogue_url, getAccessToken());
		String result = HttpPostUtil.sendGet(url, null);
		return result;
	}

	@Override
	public String getChatRecord(String starttime, String endtime, String msgid, String number) throws UnsupportedEncodingException {
		JSONObject jsonObject = new JSONObject();
		jsonObject.put("starttime", starttime);
		jsonObject.put("endtime", endtime);
		jsonObject.put("msgid", msgid);
		jsonObject.put("number", number);
		String url = mergeCustomerUrl(get_chat_record, getAccessToken());
		String result = HttpPostUtil.sendPostJSON(url, jsonObject);
		return result;
	}

}
